home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
ab20
/
sounds
/
tools
/
soundzap.lha
/
SoundZAP.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-03-29
|
11KB
|
424 lines
/************************/
/**SoundZAP Version 2.0**/
/************************/
/*
* This program was compiled with Matthew Dillon's DICE C compiler, which
* automatically opens and closes the Amiga libraries as they are needed.
* If your compiler does not do this you will have to Add the appropriate
* code (or get DICE!!).
*/
#include <exec/types.h>
#include <exec/memory.h>
#include <libraries/dos.h>
#include <stdio.h>
#include <iff/iff.h>
#include <iff/8svx.h>
#include "SoundZAP.h"
void main(int argc, char *argv[])
{
char comline[33];
struct options *Opt;
if (argc<2) GiveUsage;
if ((Opt=(UBYTE *)AllocMem(sizeof(struct options),MEMF_PUBLIC))==NULL)
CleanUp(Opt,5);
Opt->BuffSize = DEFAULT_SIZE;
Opt->FlipSign = FALSE;
Opt->KillChunk = FALSE;
Opt->SampRate = DEFAULT_RATE;
Opt->IFFOut = TRUE;
Opt->InType = UNKNOWN;
Opt->MuLaw = FALSE;
Opt->SampChk = TRUE;
Opt->Size = 0;
while (--argc > 0)
{
strcpy(comline,argv[argc]);
if (comline[0]=='-')
ProcessOpt(Opt,comline);
else
{
strcpy(Opt->outname,Opt->inname);
strcpy(Opt->inname,comline);
}
}
if (strlen(Opt->inname)==0)
GiveUsage();
if (strlen(Opt->outname)==0)
{
int l;
strcpy(Opt->outname,Opt->inname);
l=strlen(Opt->outname);
if(Opt->outname[l-4]=='.')
Opt->outname[l-4]='\0';
if(Opt->outname[l-3]=='.')
Opt->outname[l-3]='\0';
strcat(Opt->outname,".iff");
}
printf("Input File: %s\nOutput File: %s\n",Opt->inname,Opt->outname);
printf("Buffer Size: %d bytes\n",Opt->BuffSize);
if(!Opt->SampChk)
printf("Sample Rate: %d samples per second\n",Opt->SampRate);
AnalyzeData(Opt);
CleanUp(Opt,0);
}
void GiveUsage()
{
printf("Usage: SoundZAP [<options>] SOURCE [DESTINATION]\n");
printf(" (actually, the options can appear anywhere)\n\n");
printf(" options: -w Output RAW Opt->Data\n");
printf(" -s Toggle signed/unsigned output\n");
printf(" -n Don't create extra chunks in IFF output\n");
printf(" -f Assume input Opt->Data is RAW\n");
printf(" -b<n> Use a buffer size of n kilobytes\n");
printf(" -r<n> Change sample rate.\n");
printf(" where n is the sample rate or\n");
printf(" one of the built in values.\n");
printf("\n\nSee documentation for more info.\n");
printf("mrc113@psuvm.psu.edu\n");
exit(0);
}
void ProcessOpt(struct options *Opt, char com[])
{
int len;
ULONG n;
switch (com[1])
{
case 'w' : Opt->IFFOut=FALSE;
break;
case 's' : Opt->FlipSign=TRUE;
break;
case 'n' : Opt->KillChunk=TRUE;
break;
case 'f' : Opt->InType=RAW;
break;
case 'b' : len=strlen(com)-2;
if (len==0)
CleanUp(Opt,2);
n=(ULONG)atoi(com+2)*1024;
if (n!=0) Opt->BuffSize=n;
break;
case 'r' : len=strlen(com)-2;
if (len==0)
CleanUp(Opt,3);
if (len==1)
{
switch (com[2])
{
case '5' : Opt->SampRate=5696;
break;
case '7' : Opt->SampRate=7596;
break;
case '8' : Opt->SampRate=8000;
break;
case '2' : Opt->SampRate=22790;
break;
default : Opt->SampRate=11395;
}
}
else
{
n=(LONG)atoi(com+2);
if (n!=0) Opt->SampRate=n;
else Opt->SampRate=11395;
}
Opt->SampChk=FALSE;
break;
default : CleanUp(Opt,4);
}
}
void CleanUp(struct options *Opt, int Error)
{
if (Opt->Data) FreeMem(Opt->Data,Opt->BuffSize);
if (Opt) FreeMem(Opt,sizeof(struct options));
if (in) Close(in);
if (out) Close(out);
if (Error==0) exit(0);
else
{
printf("%s",ErrorMessages[Error]);
exit(20);
}
}
void AnalyzeData(struct options *Opt)
{
if ((Opt->Data=(UBYTE *)AllocMem(Opt->BuffSize,MEMF_PUBLIC))==NULL)
CleanUp(Opt,5);
if ((in=(struct FileHandle *)Open(Opt->inname,MODE_OLDFILE))==NULL)
CleanUp(Opt,6);
Read(in,Opt->Data,20);
if (Opt->InType==UNKNOWN)
{
if (!strncmp(Opt->Data,".snd",4))
ConvertAU(Opt);
else if (!strncmp(Opt->Data,"FORM",4))
/*ConvertIFF(Opt);*/ CleanUp(Opt,0);
else if (!strncmp(Opt->Data,"Creative Voice File",19))
ConvertVOC(Opt);
}
GuidoCheck(Opt);
}
/* This routine is a modified version of Guido van Rossum's (guido@cwi.nl)
* 'whatsound' routine. It guesses the sound file type (signed/unsigned/mu-law)
* by checking how the values in the file are distributed. Thanks Guido!!
*/
void GuidoCheck(struct options *Opt)
{
LONG a,n,sum;
unsigned long bin[4];
int x;
BPTR op=Output();
if(Opt->FlipSign)
{
Seek(in,0,OFFSET_END);
Opt->Size=Seek(in,0,OFFSET_BEGINNING);
ConvertRaw(Opt);
}
Write(op,"Analyzing Data...",18);
for (a=0; a<4; a++)
bin[a]=0;
do
{
n=Read(in,Opt->Data,Opt->BuffSize);
for(a=0; a<n; a++)
bin[Opt->Data[a]/64]++;
}
while (n==Opt->BuffSize);
if(bin[2]==0 && bin[3]==0)
CleanUp(Opt,7);
x=((bin[0]+bin[3])*100)/(bin[1]+bin[2]);
if(x>=300)
Opt->FlipSign=FALSE;
else if ( x <= 33)
Opt->FlipSign=TRUE;
else if ( (x >= 50) && (x <= 200))
Opt->MuLaw=TRUE;
printf("Done.\n");
if(Opt->SampChk && Opt->MuLaw) Opt->SampRate=8000;
Seek(in,0,OFFSET_END);
Opt->Size=Seek(in,0,OFFSET_BEGINNING);
ConvertRaw(Opt);
}
void ConvertRaw(struct options *Opt)
{
LONG b_read,i;
int max;
signed char logs[256];
BPTR op=Output();
if((out=(struct FileHandle *)Open(Opt->outname,MODE_NEWFILE))==NULL)
CleanUp(Opt,8);
if (Opt->IFFOut)
WriteIFFStuff(Opt);
if (Opt->MuLaw)
{
Write(op,"Building log tables...",22);
max=getscale(Opt);
maketable(logs,max);
printf("Done.\n");
if (Opt->InType==AU)
Seek(in,32,OFFSET_BEGINNING);
else
Seek(in,0,OFFSET_BEGINNING);
}
Write(op,"Converting...",13);
do
{
b_read=Read(in,Opt->Data,Opt->BuffSize);
if(Opt->FlipSign)
for (i=0; i<b_read; i++)
Opt->Data[i] ^= 0x80;
else if(Opt->MuLaw)
for (i=0; i<b_read; i++)
Opt->Data[i]=logs[Opt->Data[i]];
Write(out,Opt->Data,b_read);
}
while(b_read==Opt->BuffSize);
if(Opt->IFFOut)
Write(out,"\0\0\0",(4-Opt->Size%4)&3);
printf("Done.\n");
CleanUp(Opt,0);
}
void WriteIFFStuff(struct options *Opt)
{
int i,s;
ChunkHeader Form, V8Hdr, Body, Auth, Anno;
Voice8Header V8H = {0,0,32,8363,1,0,Unity};
if (Opt->KillChunk)
s=0;
else s=68;
Form.ckID = FORM;
Form.ckSize = 40 + s + Opt->Size + ((4-(Opt->Size%4))&3);
Write(out,&Form,8);
i=ID_8SVX;
Write(out,&i,4);
if (!Opt->KillChunk)
{
Auth.ckID = ID_AUTH;
Auth.ckSize = 16;
Write(out,&Auth,8);
Write(out,Author,16);
Anno.ckID = ID_ANNO;
Anno.ckSize = 36;
Write(out,&Anno,8);
Write(out,Annotation,36);
}
V8Hdr.ckID = ID_VHDR;
V8Hdr.ckSize = 20;
Write(out,&V8Hdr,8);
V8H.oneShotHiSamples = Opt->Size;
V8H.samplesPerSec = Opt->SampRate;
Write(out,&V8H,20);
Body.ckID = ID_BODY;
Body.ckSize = Opt->Size + ((4-(Opt->Size%4))&3);
Write(out,&Body,8);
}
void ConvertVOC(struct options *Opt)
{
UBYTE c[2];
if(Opt->SampChk)
{
Seek(in,30,OFFSET_BEGINNING);
Read(in,c,2);
if(c[1]!=0)
CleanUp(Opt,9);
Opt->SampRate=1000000/(256-c[0]);
}
Opt->FlipSign=TRUE;
Seek(in,0,OFFSET_END);
Opt->Size=Seek(in,0,OFFSET_BEGINNING)-32;
Seek(in,32,OFFSET_BEGINNING);
ConvertRaw(Opt);
}
void ConvertAU(struct options *Opt)
{
ULONG i;
int q;
Opt->MuLaw=TRUE;
Opt->InType=AU;
Seek(in,15,OFFSET_BEGINNING);
Read(in,&q,1);
if (q!=1) CleanUp(Opt,9);
Seek(in,0,OFFSET_END);
Opt->Size=Seek(in,0,OFFSET_BEGINNING)-32;
if (Opt->SampChk)
{
Seek(in,18,OFFSET_BEGINNING);
Read(in,&Opt->SampRate,2);
}
ConvertRaw(Opt);
}
/*--------------------------------------------------------------------------*
* The following routine was extracted from posting by Brian Foley. *
* Brian Foley email: bfoley@greatlakes.Central.Sun.COM *
* Systems Engineer smail: 1000 Town Center *
* Sun Microsystems Suite 1700 *
* GreatLakes Region Southfield, MI 48075 (313) 352-7070 *
*--------------------------------------------------------------------------*/
int ulaw2linear(unsigned char ulawbyte)
{
static int exp_lut[8] = { 0, 132, 396, 924, 1980, 4092, 8316, 16764 };
int sign, exponent, mantissa, sample;
ulawbyte = ~ulawbyte;
sign = ulawbyte & 0x80;
exponent = (ulawbyte >> 4) & 0x07;
mantissa = ulawbyte & 0x0F;
sample = (exp_lut[exponent] + (mantissa << (exponent + 3)));
if ( sign ) sample = -sample;
return sample;
}
int getscale(struct options *Opt)
{
int count, max = 0, i;
do
{
count = Read(in, Opt->Data, Opt->BuffSize);
for ( i = 0; i < count; i++ )
max = MAX(abs(ulaw2linear(Opt->Data[i])), max);
}
while ( count == Opt->BuffSize );
return max;
}
void maketable(signed char *logs, int max)
{
int i, c, d;
for ( i = 0; i < 256; i++ )
{
c = ( ulaw2linear(i) * ulaw2linear(0) ) / max;
d = abs(c) & 0xFF;
if ( d > 0x7F )
if ( c > 0 )
logs[i] = (signed char) ( c / 256 + 1 );
else
logs[i] = (signed char) ( c / 256 - 1 );
else
logs[i] = (signed char) ( c / 256 );
}
}